"""
设备心跳监控模块
================

该模块实现了设备心跳监控功能，可以持续监控设备连接状态。
"""

import threading
import time
from typing import Any, Dict, Optional, Callable, List
from ..utils.logger import setup_logger

logger = setup_logger(__name__)

__all__ = ['HeartbeatMonitor']


class HeartbeatMonitor:
    """
    设备心跳监控器

    该类负责监控设备连接状态，通过定期检查设备诊断信息来判断设备是否在线。
    """

    def __init__(self, device: Any = None, interval: float = 1.0) -> None:
        """
        初始化心跳监控器

        Args:
            device: 要监控的设备实例
            interval: 心跳检查间隔（秒），默认为1.0秒
        """
        self.device = device
        self._interval = interval
        self._thread: Optional[threading.Thread] = None
        self._running = False
        self._last_status = False
        self._status_lock = threading.Lock()
        self._consecutive_errors = 0
        self._max_consecutive_errors = 5
        self._status_change_callbacks: List[Callable[[bool], None]] = []

    def set_device(self, device: Any) -> None:
        """
        设置要监控的设备

        Args:
            device: 要监控的设备实例
        """
        try:
            self.device = device
        except Exception as e:
            logger.error(f"设置设备时发生异常: {e}")
            raise

    def set_interval(self, interval: float) -> None:
        """
        设置心跳检查间隔

        Args:
            interval: 心跳检查间隔（秒）
        """
        try:
            if interval <= 0:
                raise ValueError("心跳检查间隔必须大于0")
            self._interval = interval
        except ValueError as e:
            logger.error(f"设置心跳间隔时发生参数错误: {e}")
            raise
        except Exception as e:
            logger.error(f"设置心跳间隔时发生异常: {e}")
            raise

    def add_status_change_callback(self, callback: Callable[[bool], None]) -> None:
        """
        添加状态变化回调函数

        Args:
            callback: 回调函数，接收一个布尔参数表示设备状态（True表示在线，False表示离线）
        """
        try:
            if not callable(callback):
                raise TypeError("回调函数必须是可调用对象")
            with self._status_lock:
                self._status_change_callbacks.append(callback)
            logger.debug("已添加心跳状态变化回调函数")
        except Exception as e:
            logger.error(f"添加状态变化回调函数时发生异常: {e}")
            raise

    def remove_status_change_callback(self, callback: Callable[[bool], None]) -> bool:
        """
        移除状态变化回调函数

        Args:
            callback: 要移除的回调函数

        Returns:
            bool: 是否成功移除回调函数
        """
        try:
            with self._status_lock:
                if callback in self._status_change_callbacks:
                    self._status_change_callbacks.remove(callback)
                    logger.debug("已移除心跳状态变化回调函数")
                    return True
                else:
                    logger.warning("尝试移除不存在的回调函数")
                    return False
        except Exception as e:
            logger.error(f"移除状态变化回调函数时发生异常: {e}")
            return False

    def clear_status_change_callbacks(self) -> None:
        """
        清空所有状态变化回调函数
        """
        try:
            with self._status_lock:
                self._status_change_callbacks.clear()
            logger.debug("已清空所有心跳状态变化回调函数")
        except Exception as e:
            logger.error(f"清空状态变化回调函数时发生异常: {e}")
            raise

    def start_monitoring(self) -> bool:
        """
        启动心跳监控

        Returns:
            bool: 启动是否成功
        """
        try:
            if self._running and self._thread and self._thread.is_alive():
                self.stop_monitoring()

            if not self.device:
                logger.warning("未设置要监控的设备")
                return False

            self._running = True
            self._consecutive_errors = 0  # 重置错误计数
            self._thread = threading.Thread(target=self._heartbeat_worker, daemon=True)
            self._thread.start()
            logger.info(f"已启动心跳监控线程，检查间隔: {self._interval}秒")
            return True
        except Exception as e:
            logger.error(f"启动心跳监控时发生异常: {e}")
            self._running = False
            return False

    def stop_monitoring(self) -> None:
        """停止心跳监控"""
        try:
            self._running = False
            if self._thread and self._thread.is_alive():
                self._thread.join(timeout=2.0)  # 等待线程结束，最多等待2秒
            logger.info("已停止心跳监控线程")
        except Exception as e:
            logger.error(f"停止心跳监控时发生异常: {e}")
            raise

    def _notify_status_change(self, status: bool) -> None:
        """
        通知所有注册的回调函数状态已改变

        Args:
            status: 新的状态（True表示在线，False表示离线）
        """
        callbacks = []
        with self._status_lock:
            callbacks = self._status_change_callbacks.copy()

        for callback in callbacks:
            try:
                callback(status)
            except Exception as e:
                logger.error(f"执行心跳状态变化回调函数时发生异常: {e}")

    def _heartbeat_worker(self) -> None:
        """心跳监控工作线程"""
        try:
            while self._running:
                try:
                    status = self._check_heartbeat()
                    status_changed = False
                    with self._status_lock:
                        if status != self._last_status:
                            status_changed = True
                            if status:
                                logger.info("设备心跳恢复正常")
                                self._consecutive_errors = 0  # 恢复正常时重置错误计数
                            else:
                                logger.warning("设备心跳异常")

                        self._last_status = status
                        self._consecutive_errors = 0  # 成功执行检查时重置错误计数

                    # 如果状态发生变化，通知所有回调函数
                    if status_changed:
                        self._notify_status_change(status)

                except Exception as e:
                    logger.error(f"心跳监控过程中发生异常: {e}")
                    self._consecutive_errors += 1
                    status_changed = False
                    with self._status_lock:
                        if self._last_status:
                            logger.warning("设备心跳异常")
                            status_changed = True
                        self._last_status = False

                    # 如果状态发生变化，通知所有回调函数
                    if status_changed:
                        self._notify_status_change(False)

                    # 如果连续错误次数超过阈值，停止监控
                    if self._consecutive_errors >= self._max_consecutive_errors:
                        logger.error(f"连续 {self._max_consecutive_errors} 次心跳检查失败，停止监控")
                        self._running = False
                        break

                # 等待下一个检查周期
                if self._running:
                    time.sleep(self._interval)
        except Exception as e:
            logger.error(f"心跳监控工作线程发生未处理异常: {e}")
        finally:
            logger.info("心跳监控工作线程已退出")

    def _check_heartbeat(self) -> bool:
        """
        检查设备心跳状态

        Returns:
            bool: 设备是否在线
        """
        try:
            # 检查设备是否存在
            if not self.device:
                logger.warning("设备未设置，心跳异常")
                return False

            # 检查设备是否有通信接口
            if not hasattr(self.device, 'communication'):
                logger.warning("设备没有通信接口，心跳异常")
                return False

            communication = self.device.communication
            if not communication:
                logger.warning("通信接口未初始化，心跳异常")
                return False

            # 获取设备诊断信息
            if hasattr(communication, 'is_available'):
                try:
                    return communication.is_available()
                except AttributeError as e:
                    logger.error(f"通信接口缺少诊断方法: {e}")
                    return False
                except Exception as e:
                    logger.error(f"调用诊断方法时发生异常: {e}")
                    return False
            else:
                logger.warning("通信接口不支持心跳检查")
                return False

        except Exception as e:
            logger.error(f"检查心跳时发生异常: {e}")
            return False

    def get_status(self) -> bool:
        """
        获取当前心跳状态

        Returns:
            bool: 当前心跳状态
        """
        try:
            with self._status_lock:
                return self._last_status
        except Exception as e:
            logger.error(f"获取心跳状态时发生异常: {e}")
            raise

    def is_monitoring(self) -> bool:
        """
        检查心跳监控是否正在运行

        Returns:
            bool: 心跳监控是否正在运行
        """
        try:
            return self._running and self._thread and self._thread.is_alive()
        except Exception as e:
            logger.error(f"检查监控状态时发生异常: {e}")
            return False